<?php


namespace App\Service\Marketing;


use App\Enums\BaseErrorCode;
use App\Exceptions\Custom\ResponseHttpException;
use App\Models\Marketing\ShopAdvertisementMappingModel;
use App\Models\Marketing\ShopAdvertisementModel;
use App\Models\Marketing\ShopAdvertisementResourcesModel;
use App\Service\BaseService;
use App\Service\Common\OssService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Kuafu\File\FileUtil;

class ShopAdvertisementService extends BaseService
{
    public static function info(int $shopId = 0): array
    {
        $baseQuery = function () {
            return ShopAdvertisementModel::query()->with(['resourceRel'])
                                         ->where('startAt', '<', time())
                                         ->where('endAt', '>', time())
                                         ->where('status', ShopAdvertisementModel::STATUS_ENABLE);
        };

        $allShopScopeIds = $baseQuery()
            ->where('shopScope', ShopAdvertisementModel::SHOP_SCOPE_ALL)
            ->get()->pluck('id')->toArray();

        $advIds = [];
        if ($shopId) {
            $advIds = ShopAdvertisementMappingModel::query()
                                                   ->where('shopId', $shopId)
                                                   ->get()
                                                   ->pluck('advId')->unique()
                                                   ->toArray();
        }

        $ids      = array_values(array_unique(array_merge($allShopScopeIds, $advIds)));
        if (empty($ids)){
            return [];
        }
        $advModel = $baseQuery()
            ->whereIn('id', $ids)
            ->orderBy('id', 'desc')
            ->first();

        if (empty($advModel)) {
            return [];
        }
        //未登录用户展示前端判断

        $resource = collect($advModel->resourceRel)->map(function ($resource) {
            return [
                'platform' => $resource->platform,//android、ios
                'url'      => picturePath($resource->url),
                'type'     => $resource->type,// video、image
            ];
        })->toArray();

        return [
            'id'           => $advModel->id,
            'channel'      => $advModel->channel,
            'title'        => $advModel->title,
            'resource'     => $resource,
            'jumpStatus'   => $advModel->jumpStatus,
            'countDown'    => $advModel->cutDown,
            'startAt'      => formatDate($advModel->startAt),
            'endAt'        => formatDate($advModel->endAt),
            'showRule'     => $advModel->showRule,
            'notLoginShow' => $advModel->notLoginShow,
            'jumpType'     => $advModel->jumpType,
            'jumpBtnShow'  => $advModel->jumpBtnShow,
            'jumpLink'     => $advModel->jumpLink
        ];
    }

    public static function list(
        int $pageSize,
        int $pageNum,
        int $channel = null,
        string $title = null,
        int $type = null,
        int $status = null,
        string $shopIds = '',
        string $createdAtStart = '',
        string $createdAtEnd = '',
        string $createdByUids = ''
    ): array {
        $paginate = ShopAdvertisementModel::query()
                                          ->with(['resourceRel'])
                                          ->when($channel, function ($query) use ($channel) {
                                              $query->where('channel', $channel);
                                          })
                                          ->when($title, function ($query) use ($title) {
                                              $query->where('title', 'like', "%$title%");
                                          })
                                          ->when(isset($status), function ($query) use ($status) {
                                              $query->where('status', $status);
                                          })
                                          ->when($createdAtStart, function ($query) use ($createdAtStart) {
                                              $query->where(
                                                  'createdAt', '>',
                                                  Carbon::parse($createdAtStart)->startOfDay()->timestamp
                                              );
                                          })
                                          ->when($createdAtEnd, function ($query) use ($createdAtEnd) {
                                              $query->where(
                                                  'createdAt', '<',
                                                  Carbon::parse($createdAtEnd)->endOfDay()->timestamp
                                              );
                                          })
                                          ->when($createdByUids, function ($query) use ($createdByUids) {
                                              $query->whereIn('createdByUid', explode(',', $createdByUids));
                                          })
                                          ->when($shopIds, function ($query) use ($shopIds) {
                                              $_shopIds = explode(',', $shopIds);
                                              $advIds   = ShopAdvertisementMappingModel::query()
                                                                                       ->whereIn('shopId', $_shopIds)
                                                                                       ->get()
                                                                                       ->pluck('advId')->unique()
                                                                                       ->toArray();
                                              $query->where(function ($q) use ($advIds) {
                                                  if ($advIds){
                                                      $q->whereIn('id', $advIds);
                                                  }
                                                  $q->orWhere('shopScope', ShopAdvertisementModel::SHOP_SCOPE_ALL);
                                              });
                                          })
                                          ->orderBy('id', 'desc')
                                          ->paginate($pageSize, ['*'], 'page', $pageNum);

        return self::pageLists($paginate, function ($item) {
            $resource = $item->resourceRel[0] ?? null;
            return [
                'id'              => $item->id,
                'channel'         => $item->channel,
                'channelDesc'     => ShopAdvertisementModel::CHANNEL_MAP[$item->channel] ?? '',
                'title'           => $item->title,
                'type'            => $resource->type,
                'typeDesc'        => ShopAdvertisementResourcesModel::RESOURCE_TYPE_MAP[$resource->type] ?? '',
                'url'             => picturePath($resource ? $resource->url : ''),
                'status'          => $item->status,
                'statusDesc'      => ShopAdvertisementModel::STATUS_MAP[$item->status] ?? '',
                'jumpStatus'      => $item->jumpStatus,
                'jumpStatusDesc'  => ShopAdvertisementModel::JUMP_STATUS_MAP[$item->jumpStatus] ?? '',
                'jumpType'        => $item->jumpType,
                'jumpTypeDesc'    => ShopAdvertisementModel::JUMP_TYPE_MAP[$item->jumpType] ?? '',
                'cutDown'         => $item->cutDown,
                'dateRange'       => vsprintf('%s ~ %s', [
                    formatDate($item->startAt),
                    formatDate($item->endAt),
                ]),
                'showRule'        => $item->showRule,
                'showRuleDesc'    => ShopAdvertisementModel::SHOW_RULE_MAP[$item->showRule] ?? '',
                'shopScope'       => $item->shopScope,
                'shopScopeDesc'   => ShopAdvertisementModel::SHOP_SCOPE_MAP[$item->shopScope] ?? '',
                'createdAt'       => optional($item->createdAt)->format('Y-m-d H:i:s'),
                'createdUserName' => attributeGet($item, 'createdByUidRel.name', ''),
                'updatedAt'       => optional($item->updatedAt)->format('Y-m-d H:i:s'),
                'updatedUserName' => attributeGet($item, 'updatedByUidRel.name', '')
            ];
        });
    }

    /**
     * @param UploadedFile $uploadedFile
     * @param int $platform
     * @param int $type
     * @return array
     * @throws \OSS\Core\OssException
     */
    public static function upload(UploadedFile $uploadedFile, int $platform, int $type): array
    {
        if (ShopAdvertisementResourcesModel::isImage($type)
            && !in_array($uploadedFile->getMimeType(), ShopAdvertisementResourcesModel::SUPPORT_MIMETYPE_IMAGE)
        ) {
            throw new ResponseHttpException(
                BaseErrorCode::$BASE_CODE_UPDATE_FAIL, null, '上传的图片是不支持的类型'
            );
        }

        if (ShopAdvertisementResourcesModel::isImage($type)) {
            [$width, $height] = getimagesize($uploadedFile);
            $map = [
                ShopAdvertisementResourcesModel::RESOURCE_PLATFORM_ANDROID => [
                    ShopAdvertisementResourcesModel::IMAGE_ANDROID_WIDTH,
                    ShopAdvertisementResourcesModel::IMAGE_ANDROID_HEIGHT,
                ],
                ShopAdvertisementResourcesModel::RESOURCE_PLATFORM_IOS     => [
                    ShopAdvertisementResourcesModel::IMAGE_IOS_WIDTH,
                    ShopAdvertisementResourcesModel::IMAGE_IOS_HEIGHT,
                ]
            ];

            if ($map[$platform] != [(int)$width, (int)$height]) {
                throw new ResponseHttpException(
                    BaseErrorCode::$BASE_CODE_UPDATE_FAIL, null,
                    vsprintf('%s图片尺寸为%s x %s', [
                        ShopAdvertisementResourcesModel::RESOURCE_PLATFORM_MAP[$platform],
                        $map[$platform][0],
                        $map[$platform][1],
                    ])
                );
            }
        }

        $suffix = FileUtil::guessSuffix($uploadedFile->getClientOriginalName());

        $upload = OssService::uploadFile($uploadedFile->getRealPath(), $suffix);

        return [
            "path" => $upload['path'],
            "url"  => $upload['url']
        ];
    }


    public static function editInfo(int $id): array
    {
        $advModel = ShopAdvertisementModel::query()->with(['resourceRel', 'mappingRel'])
                                          ->where('id', $id)
                                          ->first();

        if (empty($advModel)) {
            self::throwErr('id异常', BaseErrorCode::$BASE_CODE_LIST_FAIL);
        }

        return [
            'title'        => $advModel->title,
            'status'       => $advModel->status,
            'channel'      => $advModel->channel,
            'jumpStatus'   => $advModel->jumpStatus,
            'cutDown'      => $advModel->cutDown,
            'startAt'      => formatDate($advModel->startAt),
            'endAt'        => formatDate($advModel->endAt),
            'showRule'     => $advModel->showRule,
            'shopScope'    => $advModel->shopScope,
            'notLoginShow' => $advModel->notLoginShow,
            'jumpType'     => $advModel->jumpType,
            'jumpRelId'    => $advModel->jumpRelId,
            'jumpBtnShow'  => $advModel->jumpBtnShow,
            'jumpLink'     => $advModel->jumpLink,
            'shopIds'      => $advModel->shopScope === ShopAdvertisementModel::SHOP_SCOPE_PART
                ? $advModel->mappingRel->pluck('shopId')->unique()->toArray()
                : [],
            'resources'    => collect($advModel->resourceRel)->map(function ($resource) {
                return [
                    'url'      => picturePath($resource->url),
                    'type'     => $resource->type,
                    'platform' => $resource->platform
                ];
            })
        ];
    }

    public static function save(array $data, int $uId): bool
    {
        $resources = [];
        foreach ($data['resources'] as $resource) {
            $resources[$resource['platform']] = [
                'platform' => $resource['platform'],
                'type'     => $resource['type'],
                'url'      => ltrim(parse_url($resource['url'], PHP_URL_PATH), '/'),
            ];
        }
        if (count($resources) !== 2) {
            self::throwErr('两个平台的资源都需要上传', BaseErrorCode::$BASE_CODE_UPDATE_FAIL);
        }

        $advId = $data['id'] ?? 0;

        DB::beginTransaction();
        try {
            $baseData = [
                'title'        => $data['title'],
                'status'       => ShopAdvertisementModel::STATUS_ENABLE,
                'channel'      => $data['channel'],
                'jumpStatus'   => $data['jumpStatus'],
                'cutDown'      => $data['cutDown'],
                'startAt'      => strtotime($data['startAt']),
                'endAt'        => strtotime($data['endAt']),
                'showRule'     => $data['showRule'],
                'shopScope'    => $data['shopScope'],
                'notLoginShow' => $data['notLoginShow'],
                'jumpType'     => $data['jumpType'],
                'jumpRelId'    => in_array(
                    $data['jumpType'],
                    [ShopAdvertisementModel::JUMP_TYPE_ARTICLE, ShopAdvertisementModel::JUMP_TYPE_FUNCTION_PAGE]
                )
                    ? ($data['jumpRelId'] ?? 0)
                    : 0,
                'jumpBtnShow'  => $data['jumpBtnShow'],
                'jumpLink'     => !empty($data['jumpLink']) ? self::buildJumpLink($data['jumpLink']) : '',
                'updatedAt'    => time(),
                'updatedByUid' => $uId,
            ];
            if ($advId) {
                ShopAdvertisementResourcesModel::query()->where('advId', $advId)->delete();
                ShopAdvertisementMappingModel::query()->where('advId', $advId)->delete();
            } else {
                $baseData['createdAt']    = time();
                $baseData['createdByUid'] = $uId;
            }

            $advId = ShopAdvertisementModel::query()->updateOrCreate(['id' => $advId], $baseData)->id;

            $insertResources = array_map(function ($item) use ($uId, $advId) {
                return array_merge($item, [
                    'advId'        => $advId,
                    'createdAt'    => time(),
                    'createdByUid' => time(),
                    'updatedAt'    => time(),
                    'updatedByUid' => $uId,
                ]);
            }, $resources);

            ShopAdvertisementResourcesModel::query()->insert($insertResources);

            if ($data['shopScope'] == ShopAdvertisementModel::SHOP_SCOPE_PART) {
                collect($data['shopIds'])->unique()->chunk(500)->each(function ($shopIds) use ($advId, $uId) {
                    $mappings = [];
                    foreach ($shopIds as $shopId) {
                        $mappings[] = [
                            'advId'        => $advId,
                            'shopId'       => $shopId,
                            'createdAt'    => time(),
                            'createdByUid' => $uId
                        ];
                    }
                    ShopAdvertisementMappingModel::query()->insert($mappings);
                });
            }
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            self::throwErr('保存异常', BaseErrorCode::$BASE_CODE_UPDATE_FAIL);
        }
        return true;
    }

    public static function buildJumpLink(string $encodeUrl): string
    {
        $decodeUrl = urldecode($encodeUrl);
        $url       = parse_url($decodeUrl);
        if (empty($url['scheme']) && empty($url['host'])){
            return $encodeUrl;
        }

        $query     = $url['query'] ?? '';
        if ($url['fragment'] ?? '') {
            $query .= "#" . $url['fragment'];
        }
        $params    = [];
        parse_str($query, $params);

        $baseUrl = vsprintf("%s://%s", [
            $url['scheme'],
            $url['host'],
        ]);

        if ($url['port'] ?? ''){
            $baseUrl .= ":".$url['port'];
        }

        if (empty($params)) {
            return vsprintf( "%s%s", [
                $baseUrl,
                $url['path'] ?? '',
            ]);
        }

        return vsprintf("%s%s?%s", [
            $baseUrl,
            $url['path'] ?? '',
            http_build_query($params)
        ]);
    }

    public static function changeStatus(int $id, int $status): bool
    {
        return (bool)ShopAdvertisementModel::query()->where('id', $id)
                                           ->update([
                                               'status'       => $status,
                                               'updatedAt'    => time(),
                                               'createdByUid' => request()->user()->id
                                           ]);
    }

}